Jelajahi JavaScript Async Iterator Helpers untuk merevolusi pemrosesan stream. Pelajari cara menangani aliran data asinkron secara efisien dengan map, filter, take, drop, dan lainnya.
JavaScript Async Iterator Helpers: Pemrosesan Stream yang Andal untuk Aplikasi Modern
Dalam pengembangan JavaScript modern, berurusan dengan aliran data asinkron adalah persyaratan umum. Baik Anda mengambil data dari API, memproses file besar, atau menangani peristiwa waktu-nyata, mengelola data asinkron secara efisien sangatlah penting. JavaScript Async Iterator Helpers menyediakan cara yang andal dan elegan untuk memproses aliran ini, menawarkan pendekatan fungsional dan dapat disusun untuk manipulasi data.
Apa itu Async Iterator dan Async Iterable?
Sebelum mendalami Async Iterator Helpers, mari kita pahami konsep dasarnya: Async Iterator dan Async Iterable.
Async Iterable adalah objek yang mendefinisikan cara untuk melakukan iterasi secara asinkron terhadap nilainya. Ini dilakukan dengan mengimplementasikan metode @@asyncIterator
, yang mengembalikan sebuah Async Iterator.
Async Iterator adalah objek yang menyediakan metode next()
. Metode ini mengembalikan promise yang me-resolve ke objek dengan dua properti:
value
: Nilai berikutnya dalam urutan.done
: Boolean yang menunjukkan apakah urutan telah sepenuhnya dikonsumsi.
Berikut adalah contoh sederhana:
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate an asynchronous operation
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
for await (const value of asyncIterable) {
console.log(value); // Output: 1, 2, 3, 4, 5 (with 500ms delay between each)
}
})();
Dalam contoh ini, generateSequence
adalah fungsi generator asinkron yang menghasilkan urutan angka secara asinkron. Loop for await...of
digunakan untuk mengonsumsi nilai dari async iterable.
Memperkenalkan Async Iterator Helpers
Async Iterator Helpers memperluas fungsionalitas Async Iterator, menyediakan serangkaian metode untuk mengubah, menyaring, dan memanipulasi aliran data asinkron. Mereka memungkinkan gaya pemrograman fungsional dan dapat disusun, membuatnya lebih mudah untuk membangun pipeline pemrosesan data yang kompleks.
Async Iterator Helpers inti meliputi:
map()
: Mengubah setiap elemen dari stream.filter()
: Memilih elemen dari stream berdasarkan suatu kondisi.take()
: Mengembalikan N elemen pertama dari stream.drop()
: Melewatkan N elemen pertama dari stream.toArray()
: Mengumpulkan semua elemen stream ke dalam sebuah array.forEach()
: Menjalankan fungsi yang disediakan sekali untuk setiap elemen stream.some()
: Memeriksa apakah setidaknya satu elemen memenuhi kondisi yang disediakan.every()
: Memeriksa apakah semua elemen memenuhi kondisi yang disediakan.find()
: Mengembalikan elemen pertama yang memenuhi kondisi yang disediakan.reduce()
: Menerapkan fungsi terhadap akumulator dan setiap elemen untuk mereduksinya menjadi satu nilai tunggal.
Mari kita jelajahi setiap helper dengan contoh.
map()
Helper map()
mengubah setiap elemen dari async iterable menggunakan fungsi yang disediakan. Ini mengembalikan async iterable baru dengan nilai-nilai yang telah diubah.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const doubledIterable = asyncIterable.map(x => x * 2);
(async () => {
for await (const value of doubledIterable) {
console.log(value); // Output: 2, 4, 6, 8, 10 (with 100ms delay)
}
})();
Dalam contoh ini, map(x => x * 2)
menggandakan setiap angka dalam urutan.
filter()
Helper filter()
memilih elemen dari async iterable berdasarkan kondisi yang disediakan (fungsi predikat). Ini mengembalikan async iterable baru yang hanya berisi elemen yang memenuhi kondisi.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const evenNumbersIterable = asyncIterable.filter(x => x % 2 === 0);
(async () => {
for await (const value of evenNumbersIterable) {
console.log(value); // Output: 2, 4, 6, 8, 10 (with 100ms delay)
}
})();
Dalam contoh ini, filter(x => x % 2 === 0)
hanya memilih angka genap dari urutan.
take()
Helper take()
mengembalikan N elemen pertama dari async iterable. Ini mengembalikan async iterable baru yang hanya berisi jumlah elemen yang ditentukan.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const firstThreeIterable = asyncIterable.take(3);
(async () => {
for await (const value of firstThreeIterable) {
console.log(value); // Output: 1, 2, 3 (with 100ms delay)
}
})();
Dalam contoh ini, take(3)
memilih tiga angka pertama dari urutan.
drop()
Helper drop()
melewatkan N elemen pertama dari async iterable dan mengembalikan sisanya. Ini mengembalikan async iterable baru yang berisi elemen yang tersisa.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const afterFirstTwoIterable = asyncIterable.drop(2);
(async () => {
for await (const value of afterFirstTwoIterable) {
console.log(value); // Output: 3, 4, 5 (with 100ms delay)
}
})();
Dalam contoh ini, drop(2)
melewatkan dua angka pertama dari urutan.
toArray()
Helper toArray()
mengonsumsi seluruh async iterable dan mengumpulkan semua elemen ke dalam sebuah array. Ini mengembalikan promise yang me-resolve ke sebuah array yang berisi semua elemen.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const numbersArray = await asyncIterable.toArray();
console.log(numbersArray); // Output: [1, 2, 3, 4, 5]
})();
Dalam contoh ini, toArray()
mengumpulkan semua angka dari urutan ke dalam sebuah array.
forEach()
Helper forEach()
menjalankan fungsi yang disediakan sekali untuk setiap elemen dalam async iterable. Ini *tidak* mengembalikan async iterable baru, melainkan menjalankan fungsi sebagai efek samping. Ini bisa berguna untuk melakukan operasi seperti logging atau memperbarui UI.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(3);
(async () => {
await asyncIterable.forEach(value => {
console.log("Value:", value);
});
console.log("forEach completed");
})();
// Output: Value: 1, Value: 2, Value: 3, forEach completed
some()
Helper some()
menguji apakah setidaknya satu elemen dalam async iterable lolos dari tes yang diimplementasikan oleh fungsi yang disediakan. Ini mengembalikan promise yang me-resolve ke nilai boolean (true
jika setidaknya satu elemen memenuhi kondisi, false
jika sebaliknya).
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const hasEvenNumber = await asyncIterable.some(x => x % 2 === 0);
console.log("Has even number:", hasEvenNumber); // Output: Has even number: true
})();
every()
Helper every()
menguji apakah semua elemen dalam async iterable lolos dari tes yang diimplementasikan oleh fungsi yang disediakan. Ini mengembalikan promise yang me-resolve ke nilai boolean (true
jika semua elemen memenuhi kondisi, false
jika sebaliknya).
async function* generateSequence(end) {
for (let i = 2; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(4);
(async () => {
const areAllEven = await asyncIterable.every(x => x % 2 === 0);
console.log("Are all even:", areAllEven); // Output: Are all even: true
})();
find()
Helper find()
mengembalikan elemen pertama dalam async iterable yang memenuhi fungsi pengujian yang disediakan. Jika tidak ada nilai yang memenuhi fungsi pengujian, undefined
akan dikembalikan. Ini mengembalikan promise yang me-resolve ke elemen yang ditemukan atau undefined
.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const firstEven = await asyncIterable.find(x => x % 2 === 0);
console.log("First even number:", firstEven); // Output: First even number: 2
})();
reduce()
Helper reduce()
menjalankan fungsi callback "reducer" yang disediakan pengguna pada setiap elemen dari async iterable, secara berurutan, dengan meneruskan nilai kembali dari perhitungan pada elemen sebelumnya. Hasil akhir dari menjalankan reducer di semua elemen adalah satu nilai tunggal. Ini mengembalikan promise yang me-resolve ke nilai terakumulasi akhir.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const sum = await asyncIterable.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log("Sum:", sum); // Output: Sum: 15
})();
Contoh Praktis dan Kasus Penggunaan
Async Iterator Helpers sangat berharga dalam berbagai skenario. Mari kita jelajahi beberapa contoh praktis:
1. Memproses Data dari API Streaming
Bayangkan Anda sedang membangun dasbor visualisasi data waktu-nyata yang menerima data dari API streaming. API tersebut mengirimkan pembaruan secara terus-menerus, dan Anda perlu memproses pembaruan ini untuk menampilkan informasi terbaru.
async function* fetchDataFromAPI(url) {
let response = await fetch(url);
if (!response.body) {
throw new Error("ReadableStream not supported in this environment");
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const chunk = decoder.decode(value);
// Assuming the API sends JSON objects separated by newlines
const lines = chunk.split('\n');
for (const line of lines) {
if (line.trim() !== '') {
yield JSON.parse(line);
}
}
}
} finally {
reader.releaseLock();
}
}
const apiURL = 'https://example.com/streaming-api'; // Replace with your API URL
const dataStream = fetchDataFromAPI(apiURL);
// Process the data stream
(async () => {
for await (const data of dataStream.filter(item => item.type === 'metric').map(item => ({ timestamp: item.timestamp, value: item.value }))) {
console.log('Processed Data:', data);
// Update the dashboard with the processed data
}
})();
Dalam contoh ini, fetchDataFromAPI
mengambil data dari API streaming, mem-parsing objek JSON, dan menghasilkannya sebagai async iterable. Helper filter
hanya memilih metrik, dan helper map
mengubah data ke format yang diinginkan sebelum memperbarui dasbor.
2. Membaca dan Memproses File Besar
Misalkan Anda perlu memproses file CSV besar yang berisi data pelanggan. Alih-alih memuat seluruh file ke dalam memori, Anda dapat menggunakan Async Iterator Helpers untuk memprosesnya sedikit demi sedikit.
async function* readLinesFromFile(filePath) {
const file = await fsPromises.open(filePath, 'r');
try {
let buffer = Buffer.alloc(1024);
let fileOffset = 0;
let remainder = '';
while (true) {
const { bytesRead } = await file.read(buffer, 0, buffer.length, fileOffset);
if (bytesRead === 0) {
if (remainder) {
yield remainder;
}
break;
}
fileOffset += bytesRead;
const chunk = buffer.toString('utf8', 0, bytesRead);
const lines = chunk.split('\n');
lines[0] = remainder + lines[0];
remainder = lines.pop() || '';
for (const line of lines) {
yield line;
}
}
} finally {
await file.close();
}
}
const filePath = './customer_data.csv'; // Replace with your file path
const lines = readLinesFromFile(filePath);
// Process the lines
(async () => {
for await (const customerData of lines.drop(1).map(line => line.split(',')).filter(data => data[2] === 'USA')) {
console.log('Customer from USA:', customerData);
// Process customer data from the USA
}
})();
Dalam contoh ini, readLinesFromFile
membaca file baris per baris dan menghasilkan setiap baris sebagai async iterable. Helper drop(1)
melewatkan baris header, helper map
membagi baris menjadi kolom, dan helper filter
hanya memilih pelanggan dari USA.
3. Menangani Peristiwa Waktu-Nyata
Async Iterator Helpers juga dapat digunakan untuk menangani peristiwa waktu-nyata dari sumber seperti WebSocket. Anda dapat membuat async iterable yang memancarkan peristiwa saat tiba dan kemudian menggunakan helper untuk memproses peristiwa ini.
async function* createWebSocketStream(url) {
const ws = new WebSocket(url);
yield new Promise((resolve, reject) => {
ws.onopen = () => {
resolve();
};
ws.onerror = (error) => {
reject(error);
};
});
try {
while (ws.readyState === WebSocket.OPEN) {
yield new Promise((resolve, reject) => {
ws.onmessage = (event) => {
resolve(JSON.parse(event.data));
};
ws.onerror = (error) => {
reject(error);
};
ws.onclose = () => {
resolve(null); // Resolve with null when connection closes
}
});
}
} finally {
ws.close();
}
}
const websocketURL = 'wss://example.com/events'; // Replace with your WebSocket URL
const eventStream = createWebSocketStream(websocketURL);
// Process the event stream
(async () => {
for await (const event of eventStream.filter(event => event.type === 'user_login').map(event => ({ userId: event.userId, timestamp: event.timestamp }))) {
console.log('User Login Event:', event);
// Process user login event
}
})();
Dalam contoh ini, createWebSocketStream
membuat async iterable yang memancarkan peristiwa yang diterima dari WebSocket. Helper filter
hanya memilih peristiwa login pengguna, dan helper map
mengubah data ke format yang diinginkan.
Manfaat Menggunakan Async Iterator Helpers
- Keterbacaan dan Keterpeliharaan Kode yang Ditingkatkan: Async Iterator Helpers mempromosikan gaya pemrograman fungsional dan dapat disusun, membuat kode Anda lebih mudah dibaca, dipahami, dan dipelihara. Sifat helper yang dapat dirangkai memungkinkan Anda untuk mengekspresikan pipeline pemrosesan data yang kompleks secara ringkas dan deklaratif.
- Penggunaan Memori yang Efisien: Async Iterator Helpers memproses aliran data secara `lazy` (malas), yang berarti mereka hanya memproses data sesuai kebutuhan. Ini dapat secara signifikan mengurangi penggunaan memori, terutama saat berhadapan dengan kumpulan data besar atau aliran data berkelanjutan.
- Peningkatan Kinerja: Dengan memproses data dalam sebuah stream, Async Iterator Helpers dapat meningkatkan kinerja dengan menghindari keharusan memuat seluruh dataset ke dalam memori sekaligus. Ini bisa sangat bermanfaat untuk aplikasi yang menangani file besar, data waktu-nyata, atau API streaming.
- Pemrograman Asinkron yang Disederhanakan: Async Iterator Helpers mengabstraksi kompleksitas pemrograman asinkron, membuatnya lebih mudah untuk bekerja dengan aliran data asinkron. Anda tidak perlu mengelola promise atau callback secara manual; helper menangani operasi asinkron di belakang layar.
- Kode yang Dapat Disusun dan Digunakan Kembali: Async Iterator Helpers dirancang untuk dapat disusun, artinya Anda dapat dengan mudah merangkainya bersama untuk membuat pipeline pemrosesan data yang kompleks. Ini mendorong penggunaan kembali kode dan mengurangi duplikasi kode.
Dukungan Browser dan Runtime
Async Iterator Helpers masih merupakan fitur yang relatif baru di JavaScript. Hingga akhir tahun 2024, mereka berada di Tahap 3 dari proses standardisasi TC39, yang berarti kemungkinan besar akan distandardisasi dalam waktu dekat. Namun, mereka belum didukung secara native di semua browser dan versi Node.js.
Dukungan Browser: Browser modern seperti Chrome, Firefox, Safari, dan Edge secara bertahap menambahkan dukungan untuk Async Iterator Helpers. Anda dapat memeriksa informasi kompatibilitas browser terbaru di situs web seperti Can I use... untuk melihat browser mana yang mendukung fitur ini.
Dukungan Node.js: Versi Node.js terbaru (v18 ke atas) menyediakan dukungan eksperimental untuk Async Iterator Helpers. Untuk menggunakannya, Anda mungkin perlu menjalankan Node.js dengan flag --experimental-async-iterator
.
Polyfill: Jika Anda perlu menggunakan Async Iterator Helpers di lingkungan yang tidak mendukungnya secara native, Anda dapat menggunakan polyfill. Polyfill adalah sepotong kode yang menyediakan fungsionalitas yang hilang. Beberapa pustaka polyfill tersedia untuk Async Iterator Helpers; pilihan populer adalah pustaka core-js
.
Mengimplementasikan Async Iterator Kustom
Meskipun Async Iterator Helpers menyediakan cara yang mudah untuk memproses async iterable yang ada, terkadang Anda mungkin perlu membuat async iterator kustom Anda sendiri. Ini memungkinkan Anda untuk menangani data dari berbagai sumber, seperti basis data, API, atau sistem file, dengan cara streaming.
Untuk membuat async iterator kustom, Anda perlu mengimplementasikan metode @@asyncIterator
pada sebuah objek. Metode ini harus mengembalikan objek dengan metode next()
. Metode next()
harus mengembalikan promise yang me-resolve ke objek dengan properti value
dan done
.
Berikut adalah contoh async iterator kustom yang mengambil data dari API berpaginasi:
async function* fetchPaginatedData(baseURL) {
let page = 1;
let hasMore = true;
while (hasMore) {
const url = `${baseURL}?page=${page}`;
const response = await fetch(url);
const data = await response.json();
if (data.results.length === 0) {
hasMore = false;
break;
}
for (const item of data.results) {
yield item;
}
page++;
}
}
const apiBaseURL = 'https://api.example.com/data'; // Replace with your API URL
const paginatedData = fetchPaginatedData(apiBaseURL);
// Process the paginated data
(async () => {
for await (const item of paginatedData) {
console.log('Item:', item);
// Process the item
}
})();
Dalam contoh ini, fetchPaginatedData
mengambil data dari API berpaginasi, menghasilkan setiap item saat diambil. Async iterator menangani logika paginasi, membuatnya mudah untuk mengonsumsi data dengan cara streaming.
Tantangan dan Pertimbangan Potensial
Meskipun Async Iterator Helpers menawarkan banyak manfaat, penting untuk menyadari beberapa tantangan dan pertimbangan potensial:
- Penanganan Kesalahan: Penanganan kesalahan yang tepat sangat penting saat bekerja dengan aliran data asinkron. Anda perlu menangani potensi kesalahan yang mungkin terjadi selama pengambilan, pemrosesan, atau transformasi data. Menggunakan blok
try...catch
dan teknik penanganan kesalahan dalam helper async iterator Anda sangat penting. - Pembatalan: Dalam beberapa skenario, Anda mungkin perlu membatalkan pemrosesan async iterable sebelum sepenuhnya dikonsumsi. Ini bisa berguna saat berhadapan dengan operasi yang berjalan lama atau aliran data waktu-nyata di mana Anda ingin berhenti memproses setelah kondisi tertentu terpenuhi. Menerapkan mekanisme pembatalan, seperti menggunakan
AbortController
, dapat membantu Anda mengelola operasi asinkron secara efektif. - Backpressure: Saat berhadapan dengan aliran data yang menghasilkan data lebih cepat daripada yang dapat dikonsumsi, backpressure menjadi perhatian. Backpressure mengacu pada kemampuan konsumen untuk memberi sinyal kepada produsen untuk memperlambat laju data yang dipancarkan. Menerapkan mekanisme backpressure dapat mencegah kelebihan memori dan memastikan bahwa aliran data diproses secara efisien.
- Debugging: Men-debug kode asinkron bisa lebih menantang daripada men-debug kode sinkron. Saat bekerja dengan Async Iterator Helpers, penting untuk menggunakan alat dan teknik debugging untuk melacak alur data melalui pipeline dan mengidentifikasi potensi masalah.
Praktik Terbaik untuk Menggunakan Async Iterator Helpers
Untuk mendapatkan hasil maksimal dari Async Iterator Helpers, pertimbangkan praktik terbaik berikut:
- Gunakan Nama Variabel yang Deskriptif: Pilih nama variabel yang deskriptif yang dengan jelas menunjukkan tujuan dari setiap async iterable dan helper. Ini akan membuat kode Anda lebih mudah dibaca dan dipahami.
- Jaga Agar Fungsi Helper Tetap Ringkas: Jaga agar fungsi yang diteruskan ke Async Iterator Helpers seringkas dan sefokus mungkin. Hindari melakukan operasi kompleks di dalam fungsi-fungsi ini; sebaliknya, buat fungsi terpisah untuk logika yang kompleks.
- Rangkai Helper untuk Keterbacaan: Rangkai Async Iterator Helpers bersama-sama untuk membuat pipeline pemrosesan data yang jelas dan deklaratif. Hindari menyarangkan helper secara berlebihan, karena ini dapat membuat kode Anda lebih sulit dibaca.
- Tangani Kesalahan dengan Baik: Terapkan mekanisme penanganan kesalahan yang tepat untuk menangkap dan menangani potensi kesalahan yang mungkin terjadi selama pemrosesan data. Berikan pesan kesalahan yang informatif untuk membantu mendiagnosis dan menyelesaikan masalah.
- Uji Kode Anda Secara Menyeluruh: Uji kode Anda secara menyeluruh untuk memastikan bahwa ia menangani berbagai skenario dengan benar. Tulis tes unit untuk memverifikasi perilaku masing-masing helper dan tes integrasi untuk memverifikasi pipeline pemrosesan data secara keseluruhan.
Teknik Tingkat Lanjut
Menyusun Helper Kustom
Anda dapat membuat helper async iterator kustom Anda sendiri dengan menyusun helper yang ada atau membangun yang baru dari awal. Ini memungkinkan Anda untuk menyesuaikan fungsionalitas dengan kebutuhan spesifik Anda dan membuat komponen yang dapat digunakan kembali.
async function* takeWhile(asyncIterable, predicate) {
for await (const value of asyncIterable) {
if (!predicate(value)) {
break;
}
yield value;
}
}
// Example Usage:
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const firstFive = takeWhile(asyncIterable, x => x <= 5);
(async () => {
for await (const value of firstFive) {
console.log(value);
}
})();
Menggabungkan Beberapa Async Iterable
Anda dapat menggabungkan beberapa async iterable menjadi satu async iterable tunggal menggunakan teknik seperti zip
atau merge
. Ini memungkinkan Anda untuk memproses data dari beberapa sumber secara bersamaan.
async function* zip(asyncIterable1, asyncIterable2) {
const iterator1 = asyncIterable1[Symbol.asyncIterator]();
const iterator2 = asyncIterable2[Symbol.asyncIterator]();
while (true) {
const result1 = await iterator1.next();
const result2 = await iterator2.next();
if (result1.done || result2.done) {
break;
}
yield [result1.value, result2.value];
}
}
// Example Usage:
async function* generateSequence1(end) {
for (let i = 1; i <= end; i++) {
yield i;
}
}
async function* generateSequence2(end) {
for (let i = 10; i <= end + 9; i++) {
yield i;
}
}
const iterable1 = generateSequence1(5);
const iterable2 = generateSequence2(5);
(async () => {
for await (const [value1, value2] of zip(iterable1, iterable2)) {
console.log(value1, value2);
}
})();
Kesimpulan
JavaScript Async Iterator Helpers menyediakan cara yang andal dan elegan untuk memproses aliran data asinkron. Mereka menawarkan pendekatan fungsional dan dapat disusun untuk manipulasi data, membuatnya lebih mudah untuk membangun pipeline pemrosesan data yang kompleks. Dengan memahami konsep inti Async Iterator dan Async Iterable dan menguasai berbagai metode helper, Anda dapat secara signifikan meningkatkan efisiensi dan keterpeliharaan kode JavaScript asinkron Anda. Seiring dengan terus berkembangnya dukungan browser dan runtime, Async Iterator Helpers siap menjadi alat penting bagi pengembang JavaScript modern.